package org.asociacion.backend.persistence.impl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import org.asociacion.backend.persistence.GenericDao;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

public class GenericDaoImpl<T, PK extends Serializable> implements GenericDao<T, PK> {
	
	private SessionFactory sessionFactory;
	private Class<T> type;
	
	public GenericDaoImpl(SessionFactory sessionFactory){
		this.sessionFactory = sessionFactory;
	}
	
	@SuppressWarnings("unchecked")
	public Class<T> getType() {
		if (type == null) {
			Class<?> clazz = getClass();
			while (!(clazz.getGenericSuperclass() instanceof ParameterizedType)) {
				clazz = (Class<T>) clazz.getSuperclass();
			}
			type = (Class<T>) ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[0];
		} 
		return type;
	}
	
	protected Session getCurrentSession() {
		return sessionFactory.getCurrentSession();
	}
	
	protected Criteria getCriteria() {
		return getCurrentSession().createCriteria(getType());
	}

	@Override
	public void create(T obj) {
		sessionFactory.getCurrentSession().save(obj);
	}

	@SuppressWarnings("unchecked")
	@Override
	public T read(PK id) {
		return (T) sessionFactory.getCurrentSession().get(getType(), id);
	}

	@Override
	public void update(T obj) {
		sessionFactory.getCurrentSession().update(obj);
	}

	@Override
	public void delete(T obj) {
		sessionFactory.getCurrentSession().delete(obj);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> list() {
		return (List<T>)sessionFactory.getCurrentSession().createQuery("from "+ getType().getName()).list() ;
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<T> list(int start, int max) {
		Query query = sessionFactory.getCurrentSession().createQuery("from "+ getType().getName());
		query.setFirstResult(start);
		query.setMaxResults(max);
		return (List<T>)query.list();
	}

	@Override
	public Integer getCount() {
		return (Integer)sessionFactory.getCurrentSession().createQuery("select count from " + getType().getName()).uniqueResult() ;
	}

}
